package org.example.compare.service.impl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.example.compare.dto.DateWorkTime;
import org.example.compare.dto.WorkTimeDto;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 测试数据生成器类，用于生成capDateWorkTime函数的测试数据
 */
public class CapDateWorkTimeTestDataGenerator {

    private static final ObjectMapper objectMapper = new ObjectMapper();

    static {
        objectMapper.registerModule(new JavaTimeModule());
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
    }

    /**
     * 根据年份和月份随机生成该月的有效日期
     *
     * @param year  年份
     * @param month 月份 (1-12)
     * @return 该月的随机日期
     */
    private static Date generateRandomDateInMonth(int year, int month) {
        Calendar cal = Calendar.getInstance();
        // 获取该月的最大天数
        cal.set(year, month - 1, 1);
        int maxDay = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
        // 随机生成该月的一天
        int randomDay = 1 + new Random().nextInt(maxDay);
        cal.set(year, month - 1, randomDay, 0, 0, 0);
        cal.set(Calendar.MILLISECOND, 0);
        return cal.getTime();
    }

    /**
     * 随机生成2025年的有效日期
     *
     * @return 随机生成的日期
     */
    private static Date generateRandomDate2025() {
        Random random = new Random();
        int month = random.nextInt(12) + 1;
        return generateRandomDateInMonth(2025, month);
    }

    /**
     * 生成不重叠的时间段
     *
     * @param random   随机数生成器
     * @param minSlots 最小时间段数
     * @param maxSlots 最大时间段数
     * @return 不重叠的时间段列表
     */
    private static List<WorkTimeDto> generateNonOverlappingTimeSlots(Random random, int minSlots, int maxSlots) {
        List<WorkTimeDto> workTimes = new ArrayList<>();

        // 随机生成时间段数量
        int slotCount = minSlots + random.nextInt(maxSlots - minSlots + 1);

        // 生成不重叠的时间段
        List<int[]> timeSlots = new ArrayList<>();
        int currentTime = 7 * 60; // 起始时间7:00(以分钟为单位)
        int endTime = 21 * 60;    // 结束时间21:00(以分钟为单位)

        for (int i = 0; i < slotCount && currentTime < endTime - 30; i++) { // 确保至少有30分钟生成时间段
            // 计算剩余可分配时间
            int remainingTime = endTime - currentTime;
            int remainingSlots = slotCount - i;

            // 确保不会出现负数或零的情况
            if (remainingSlots <= 0 || remainingTime <= 0) {
                break;
            }

            // 生成起始时间(在当前时间和结束时间之间)
            int maxInterval = Math.max(1, remainingTime / remainingSlots);
            int startMinute = currentTime + random.nextInt(maxInterval);

            // 确保不会超出结束时间
            if (startMinute >= endTime) {
                break;
            }

            // 生成持续时间(30分钟到4小时，但不超过剩余时间)
            int maxDuration = Math.min(210, endTime - startMinute - 1);
            if (maxDuration < 30) { // 如果剩余时间不足30分钟，跳过
                break;
            }
            int duration = 30 + random.nextInt(maxDuration - 30 + 1);
            int endMinute = startMinute + duration;

            // 确保结束时间不超过限制
            if (endMinute > endTime) {
                endMinute = endTime;
            }

            // 如果时间段有效，则添加
            if (endMinute > startMinute) {
                timeSlots.add(new int[]{startMinute, endMinute});
                // 更新当前时间，确保下一个时间段不会重叠
                currentTime = endMinute + 10 + random.nextInt(30); // 至少间隔10分钟，最多40分钟
            } else {
                break;
            }
        }


        // 创建WorkTimeDto对象
        for (int[] slot : timeSlots) {
            int startHour = slot[0] / 60;
            int startMinute = slot[0] % 60;
            int endHour = slot[1] / 60;
            int endMinute = slot[1] % 60;

            WorkTimeDto workTimeDto = new WorkTimeDto();
            workTimeDto.update(
                    new java.sql.Time(startHour, startMinute, 0),
                    new java.sql.Time(endHour, endMinute, 0)
            );
            workTimes.add(workTimeDto);
        }

        return workTimes;
    }


    /**
     * 生成全局变量测试数据并保存到文件
     */
    public static void generateGlobalTestData(int iteration) throws IOException {
        String basePath = "../../test_data/capDateWorkTime/random_case_" + iteration;
        File baseDir = new File(basePath);
        if (!baseDir.exists()) {
            baseDir.mkdirs();
        }

        // 生成特殊日期工作时间数据
        List<DateWorkTime> specialDateWorkTimes = new ArrayList<>();

        Random random = new Random();

        // 随机生成1-20个特殊日期
        int specialDateCount = random.nextInt(20) + 1;
        for (int i = 0; i < specialDateCount; i++) {
            // 使用抽象方法生成随机日期
            Date date = generateRandomDate2025();

            // 为该日期生成1-3个不重叠的工作时间段
            List<WorkTimeDto> specialWorkTimes = generateNonOverlappingTimeSlots(random, 1, 3);

            // 为每个时间段创建一个DateWorkTime对象
            for (WorkTimeDto workTimeDto : specialWorkTimes) {
                DateWorkTime dateWorkTime = new DateWorkTime();
                dateWorkTime.setAppointedDate(date);

                // 设置该时间段的工作时间
                Calendar cal = Calendar.getInstance();
                cal.setTime(date);

                // 设置开始时间
                cal.set(Calendar.HOUR_OF_DAY, workTimeDto.mWorkStartTime.getHours());
                cal.set(Calendar.MINUTE, workTimeDto.mWorkStartTime.getMinutes());
                cal.set(Calendar.SECOND, workTimeDto.mWorkStartTime.getSeconds());
                cal.set(Calendar.MILLISECOND, 0);
                dateWorkTime.setWorkTimeStart(cal.getTime());

                // 设置结束时间
                cal.set(Calendar.HOUR_OF_DAY, workTimeDto.mWorkEndTime.getHours());
                cal.set(Calendar.MINUTE, workTimeDto.mWorkEndTime.getMinutes());
                cal.set(Calendar.SECOND, workTimeDto.mWorkEndTime.getSeconds());
                cal.set(Calendar.MILLISECOND, 0);
                dateWorkTime.setWorkTimeEnd(cal.getTime());

                specialDateWorkTimes.add(dateWorkTime);
            }
        }


        // 保存特殊日期工作时间数据到文件
        objectMapper.writeValue(new File(basePath + "/special_date_work_time.json"), specialDateWorkTimes);

        // 生成常规每周工作时间数据
        Map<Integer, List<WorkTimeDto>> normalWorkTime = new HashMap<>();

        // 工作日固定为1-5（周一到周五）
        List<Integer> workDays = Arrays.asList(1, 2, 3, 4, 5);

        // 为每个工作日设置随机工作时间(1-3个时间段)
        for (Integer day : workDays) {
            List<WorkTimeDto> workTimes = generateNonOverlappingTimeSlots(random, 1, 3);
            normalWorkTime.put(day, workTimes);
        }

        // 转换为可序列化的格式
        Map<Integer, List<Map<String, String>>> serializableNormalWorkTime = new HashMap<>();
        for (Map.Entry<Integer, List<WorkTimeDto>> entry : normalWorkTime.entrySet()) {
            List<Map<String, String>> workTimeList = new ArrayList<>();
            for (WorkTimeDto workTimeDto : entry.getValue()) {
                Map<String, String> workTimeMap = new HashMap<>();
                workTimeMap.put("startTime", workTimeDto.mWorkStartTime.toString());
                workTimeMap.put("endTime", workTimeDto.mWorkEndTime.toString());
                workTimeList.add(workTimeMap);
            }
            serializableNormalWorkTime.put(entry.getKey(), workTimeList);
        }

        // 保存常规工作时间数据到文件
        objectMapper.writeValue(new File(basePath + "/normal_work_time.json"), serializableNormalWorkTime);

        // 生成节假日数据
        Set<Date> holidays = new HashSet<>();
        // 随机生成5-10个节假日
        int holidayCount = random.nextInt(6) + 5;
        for (int i = 0; i < holidayCount; i++) {
            // 使用抽象方法生成随机日期
            holidays.add(generateRandomDate2025());
        }

        // 转换为可序列化的格式
        List<String> holidayStrings = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        for (Date holiday : holidays) {
            holidayStrings.add(sdf.format(holiday));
        }

        // 保存节假日数据到文件
        objectMapper.writeValue(new File(basePath + "/holidays.json"), holidayStrings);
    }

    /**
     * 生成函数输入测试数据并保存到文件
     */
    public static void generateFunctionInputTestData(int iteration) throws IOException {
        String basePath = "../../test_data/capDateWorkTime/random_case_" + iteration;
        File baseDir = new File(basePath);
        if (!baseDir.exists()) {
            baseDir.mkdirs();
        }

        Map<String, Object> testData = new HashMap<>();
        List<Map<String, Object>> testCases = new ArrayList<>();
        Random random = new Random();

        // 生成一个测试用例
        Map<String, Object> testCase = new HashMap<>();

        // 使用抽象方法生成随机起始日期
        Date startDate = generateRandomDate2025();

        // 使用抽象方法生成随机结束日期，但确保不早于起始日期
        Date endDate;
        do {
            endDate = generateRandomDate2025();
        } while (endDate.before(startDate));

        testCase.put("startDate", startDate);
        testCase.put("endDate", endDate);
        testCase.put("description", "随机生成的测试用例");

        testCases.add(testCase);
        testData.put("testCases", testCases);

        // 保存测试用例数据到文件
        objectMapper.writeValue(new File(basePath + "/test_cases.json"), testData);
    }

    /**
     * 生成手动测试案例数据并保存到文件
     */
    public static void generateManualTestData(int caseNumber) throws IOException {
        String basePath = "../../test_data/capDateWorkTime/manual_case_" + caseNumber;
        File baseDir = new File(basePath);
        if (!baseDir.exists()) {
            baseDir.mkdirs();
        }

        // 生成特殊日期工作时间数据
        List<DateWorkTime> specialDateWorkTimes = new ArrayList<>();
        Random random = new Random();

        // 手动案例1: 包含特殊工作日
        if (caseNumber == 1) {
            // 生成5个特殊日期
            int[][] specialDates1 = {
                    {2025, Calendar.NOVEMBER, 11},
                    {2025, Calendar.DECEMBER, 25},
                    {2025, Calendar.JANUARY, 1},
                    {2025, Calendar.MAY, 1},
                    {2025, Calendar.OCTOBER, 1}
            };

            for (int[] dateInfo : specialDates1) {
                Calendar cal = Calendar.getInstance();
                cal.set(dateInfo[0], dateInfo[1], dateInfo[2], 0, 0, 0);
                cal.set(Calendar.MILLISECOND, 0);
                Date date = cal.getTime();

                // 为该日期生成1-3个不重叠的工作时间段
                List<WorkTimeDto> specialWorkTimes = generateNonOverlappingTimeSlots(random, 1, 3);

                // 为每个时间段创建一个DateWorkTime对象
                for (WorkTimeDto workTimeDto : specialWorkTimes) {
                    DateWorkTime dateWorkTime = new DateWorkTime();
                    dateWorkTime.setAppointedDate(date);

                    // 设置该时间段的工作时间
                    Calendar workCal = Calendar.getInstance();
                    workCal.setTime(date);

                    // 设置开始时间
                    workCal.set(Calendar.HOUR_OF_DAY, workTimeDto.mWorkStartTime.getHours());
                    workCal.set(Calendar.MINUTE, workTimeDto.mWorkStartTime.getMinutes());
                    workCal.set(Calendar.SECOND, workTimeDto.mWorkStartTime.getSeconds());
                    workCal.set(Calendar.MILLISECOND, 0);
                    dateWorkTime.setWorkTimeStart(workCal.getTime());

                    // 设置结束时间
                    workCal.set(Calendar.HOUR_OF_DAY, workTimeDto.mWorkEndTime.getHours());
                    workCal.set(Calendar.MINUTE, workTimeDto.mWorkEndTime.getMinutes());
                    workCal.set(Calendar.SECOND, workTimeDto.mWorkEndTime.getSeconds());
                    workCal.set(Calendar.MILLISECOND, 0);
                    dateWorkTime.setWorkTimeEnd(workCal.getTime());

                    specialDateWorkTimes.add(dateWorkTime);
                }
            }
        }
        // 手动案例2: 包含跨年日期
        else if (caseNumber == 2) {
            // 生成5个特殊日期
            int[][] specialDates2 = {
                    {2025, Calendar.DECEMBER, 31},
                    {2025, Calendar.JANUARY, 1},
                    {2025, Calendar.FEBRUARY, 14},
                    {2025, Calendar.JULY, 4},
                    {2025, Calendar.SEPTEMBER, 15}
            };

            for (int[] dateInfo : specialDates2) {
                Calendar cal = Calendar.getInstance();
                cal.set(dateInfo[0], dateInfo[1], dateInfo[2], 0, 0, 0);
                cal.set(Calendar.MILLISECOND, 0);
                Date date = cal.getTime();

                // 为该日期生成1-3个不重叠的工作时间段
                List<WorkTimeDto> specialWorkTimes = generateNonOverlappingTimeSlots(random, 1, 3);

                // 为每个时间段创建一个DateWorkTime对象
                for (WorkTimeDto workTimeDto : specialWorkTimes) {
                    DateWorkTime dateWorkTime = new DateWorkTime();
                    dateWorkTime.setAppointedDate(date);

                    // 设置该时间段的工作时间
                    Calendar workCal = Calendar.getInstance();
                    workCal.setTime(date);

                    // 设置开始时间
                    workCal.set(Calendar.HOUR_OF_DAY, workTimeDto.mWorkStartTime.getHours());
                    workCal.set(Calendar.MINUTE, workTimeDto.mWorkStartTime.getMinutes());
                    workCal.set(Calendar.SECOND, workTimeDto.mWorkStartTime.getSeconds());
                    workCal.set(Calendar.MILLISECOND, 0);
                    dateWorkTime.setWorkTimeStart(workCal.getTime());

                    // 设置结束时间
                    workCal.set(Calendar.HOUR_OF_DAY, workTimeDto.mWorkEndTime.getHours());
                    workCal.set(Calendar.MINUTE, workTimeDto.mWorkEndTime.getMinutes());
                    workCal.set(Calendar.SECOND, workTimeDto.mWorkEndTime.getSeconds());
                    workCal.set(Calendar.MILLISECOND, 0);
                    dateWorkTime.setWorkTimeEnd(workCal.getTime());

                    specialDateWorkTimes.add(dateWorkTime);
                }
            }
        }

        // 保存特殊日期工作时间数据到文件
        objectMapper.writeValue(new File(basePath + "/special_date_work_time.json"), specialDateWorkTimes);

        // 生成常规每周工作时间数据(工作日固定为1-5)
        Map<Integer, List<WorkTimeDto>> normalWorkTime = new HashMap<>();
        List<Integer> workDays = Arrays.asList(1, 2, 3, 4, 5);

        // 为每个工作日设置1-3个工作时间段
        for (Integer day : workDays) {
            List<WorkTimeDto> workTimes = generateNonOverlappingTimeSlots(random, 1, 3);
            normalWorkTime.put(day, workTimes);
        }

        // 转换为可序列化的格式
        Map<Integer, List<Map<String, String>>> serializableNormalWorkTime = new HashMap<>();
        for (Map.Entry<Integer, List<WorkTimeDto>> entry : normalWorkTime.entrySet()) {
            List<Map<String, String>> workTimeList = new ArrayList<>();
            for (WorkTimeDto workTimeDto : entry.getValue()) {
                Map<String, String> workTimeMap = new HashMap<>();
                workTimeMap.put("startTime", workTimeDto.mWorkStartTime.toString());
                workTimeMap.put("endTime", workTimeDto.mWorkEndTime.toString());
                workTimeList.add(workTimeMap);
            }
            serializableNormalWorkTime.put(entry.getKey(), workTimeList);
        }

        // 保存常规工作时间数据到文件
        objectMapper.writeValue(new File(basePath + "/normal_work_time.json"), serializableNormalWorkTime);

        // 生成节假日数据
        Set<Date> holidays = new HashSet<>();

        if (caseNumber == 1) {
            // 案例1的节假日(5个)
            int[][] holidayDates1 = {
                    {2025, Calendar.JANUARY, 1},
                    {2025, Calendar.MAY, 1},
                    {2025, Calendar.JULY, 4},
                    {2025, Calendar.SEPTEMBER, 15},
                    {2025, Calendar.DECEMBER, 25}
            };

            for (int[] dateInfo : holidayDates1) {
                Calendar cal = Calendar.getInstance();
                cal.set(dateInfo[0], dateInfo[1], dateInfo[2], 0, 0, 0);
                cal.set(Calendar.MILLISECOND, 0);
                holidays.add(cal.getTime());
            }
        } else if (caseNumber == 2) {
            // 案例2的节假日(5个)
            int[][] holidayDates2 = {
                    {2025, Calendar.OCTOBER, 1},
                    {2025, Calendar.NOVEMBER, 11},
                    {2025, Calendar.DECEMBER, 25},
                    {2025, Calendar.FEBRUARY, 14},
                    {2025, Calendar.JULY, 4}
            };

            for (int[] dateInfo : holidayDates2) {
                Calendar cal = Calendar.getInstance();
                cal.set(dateInfo[0], dateInfo[1], dateInfo[2], 0, 0, 0);
                cal.set(Calendar.MILLISECOND, 0);
                holidays.add(cal.getTime());
            }
        }

        // 转换为可序列化的格式
        List<String> holidayStrings = new ArrayList<>();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        for (Date holiday : holidays) {
            holidayStrings.add(sdf.format(holiday));
        }

        // 保存节假日数据到文件
        objectMapper.writeValue(new File(basePath + "/holidays.json"), holidayStrings);
    }


    /**
     * 生成手动测试案例的函数输入数据并保存到文件
     */
    public static void generateManualFunctionInputTestData(int caseNumber) throws IOException {
        String basePath = "../../test_data/capDateWorkTime/manual_case_" + caseNumber;
        File baseDir = new File(basePath);
        if (!baseDir.exists()) {
            baseDir.mkdirs();
        }

        Map<String, Object> testData = new HashMap<>();
        List<Map<String, Object>> testCases = new ArrayList<>();

        // 生成测试用例
        Map<String, Object> testCase = new HashMap<>();

        if (caseNumber == 1) {
            // 案例1: 起始日期晚于结束日期的异常情况
            Calendar startCal = Calendar.getInstance();
            startCal.set(2025, Calendar.NOVEMBER, 15, 0, 0, 0);
            startCal.set(Calendar.MILLISECOND, 0);
            testCase.put("startDate", startCal.getTime());

            Calendar endCal = Calendar.getInstance();
            endCal.set(2025, Calendar.NOVEMBER, 10, 0, 0, 0);
            endCal.set(Calendar.MILLISECOND, 0);
            testCase.put("endDate", endCal.getTime());
            testCase.put("description", "起始日期晚于结束日期的异常测试案例");
        } else if (caseNumber == 2) {
            // 案例2: 正常的日期范围（起始日期早于结束日期）
            Calendar startCal = Calendar.getInstance();
            startCal.set(2025, Calendar.DECEMBER, 20, 0, 0, 0);
            startCal.set(Calendar.MILLISECOND, 0);
            testCase.put("startDate", startCal.getTime());

            Calendar endCal = Calendar.getInstance();
            endCal.set(2026, Calendar.JANUARY, 5, 0, 0, 0);
            endCal.set(Calendar.MILLISECOND, 0);
            testCase.put("endDate", endCal.getTime());
            testCase.put("description", "正常的跨年日期范围测试案例");
        }

        testCases.add(testCase);
        testData.put("testCases", testCases);

        // 保存测试用例数据到文件
        objectMapper.writeValue(new File(basePath + "/test_cases.json"), testData);
    }


    public static void main(String[] args) {
        try {
            // 确保主目录存在
            File mainDir = new File("../../test_data/capDateWorkTime");
            if (!mainDir.exists()) {
                mainDir.mkdirs();
            }

            // 生成50组随机测试数据
            for (int i = 1; i <= 50; i++) {
                // 检查是否存在以random_case_i命名的文件夹，没有则创建
                String casePath = "../../test_data/capDateWorkTime/random_case_" + i;
                File caseDir = new File(casePath);
                if (!caseDir.exists()) {
                    caseDir.mkdirs();
                }

                generateGlobalTestData(i);
                generateFunctionInputTestData(i);
                System.out.println("测试数据集 " + i + " 已成功生成并保存到 " + casePath);
            }
            for (int i = 1; i <= 2; i++) {
                generateManualTestData(i);
                generateManualFunctionInputTestData(i);
            }
            System.out.println("所有50组测试数据已成功生成并保存到../../test_data/capDateWorkTime目录下");
        } catch (IOException e) {
            System.err.println("生成测试数据时发生错误: " + e.getMessage());
            e.printStackTrace();
        }
    }
}
